//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Module name			: System
// Date (dd.Mmm.yyyy)	: 25.02.2012
// Owner				: Jesper Bangsholt
// 						:
// Description			: System functions
// MTS document			: <mts.pdf> alternative <none>
// MRS document			: <mrs.pdf> alternative <none>
// FID document			: <fid.pdf> alternative <none>
// GMD document			: <gmd.pdf> alternative <none>
//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Include files
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "System.h"
#include "Define.h"

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Local typedefs
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Local defines
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#define defPinIn 			"in"						//String to set pin to input
#define defPinOut			"out"						//String to set pin to output
#define defValueHigh		"1"							//String to set pin high
#define defValueLow			"0"							//String to set pin low
#define defExport			"/sys/class/gpio/export"	//String to create pin
#define defUnexport			"/sys/class/gpio/unexport"	//String to remove pin
#define defPath				"/sys/class/gpio/gpio"		//String to the gpio pin
#define defDirection		"/direction"				//String to set direction
#define defValue			"/value"					//String to set value
#define defLedPath			"/sys/class/leds/"			//String to Leds folder
#define defLedBrightness	"/brightness"				//String to brightness file
#define defLedTrigger		"/trigger"					//String to trigger file
#define defSelectDirection	0							//Int to signify direction
#define defSelectValue		1							//Int to signify pin
#define defSelectBrightness 0							//Int to select brightness
#define defSelectTrigger	1							//Int to select trigger
#define	defLedOn	"1"									//Value to turn on Led
#define defLedOff	"0"									//Value to turn off Led
//#define DEBUG											//To get additional printfs, uncomment this

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Local variables
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
char result[40]; //Holds the current path to the current file.

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Local constants
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Local function prototyping
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void writeExportFile(int PortNumber);
void writeDirectionFile(int PortNumber, int Direction);
void writeValueFile(int PortNumber, int Value);
void writeGpioPath(int PortNumber, int Select);
int readValueFile(int PortNumber);
void removePort(int PortNumber);
void TurnLedOn(int Led);
void TurnLedOff(int Led);
void SetLedTrigger(int Led, int Trigger);
void writeLedPath(int Led, int Selection);
int readBrightnessFile(int Led);
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Global functions
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : System_CreateGpioPin
// Date (dd-mm-yyyy)    : 25.02.2012
// Function description : Will create a new GPIO pin and intialize it with given values
// In-/Output           : PortNumber	: The port to initialize
//						: Direction		: The direction of the port. defPinIn / defPinOut
//						: InitialValue	: The initial value of the port. defPinHigh / defPinLow
//--------------------------------------------------------------------------------------------------------------------------
void System_CreateGpioPin(int PortNumber, int Direction, int InitialValue)
{
	writeExportFile(PortNumber);
	writeDirectionFile(PortNumber, Direction);
	writeValueFile(PortNumber, InitialValue);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : System_SetValue
// Date (dd-mm-yyyy)    : 25.02.2012
// Function description : Sets the value on the port
// In-/Output           : PortNumber	: The port number to set the value on
//						: Value			: The value to set to the port
//--------------------------------------------------------------------------------------------------------------------------
void System_SetValue(int PortNumber, int Value)
{
	writeValueFile(PortNumber, Value);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : System_TogglePin
// Date (dd-mm-yyyy)    : 25.02.2012
// Function description : Toggles the PortNumber
// In-/Output           : PortNumber	: The Port number to toggle
//--------------------------------------------------------------------------------------------------------------------------
void System_TogglePin(int PortNumber)
{
	//Check what the value is, and set it to the opposite
	if(readValueFile(PortNumber) == 1)
	{
		writeValueFile(PortNumber, defPinLow);
	}
	else
	{
		writeValueFile(PortNumber, defPinHigh);
	}
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : System_ReadValue
// Date (dd-mm-yyyy)    : 25.02.2012
// Function description : Reads the value from PortNumber
// In-/Output           : PortNumber	: The port to read from
//--------------------------------------------------------------------------------------------------------------------------
int System_ReadValue(int PortNumber)
{
	return readValueFile(PortNumber);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : System_RemoveGpioPin
// Date (dd-mm-yyyy)    : 26.02.2012
// Function description : Removes the Gpio Pin if there is no longer a use for it
// In-/Output           : PortNumber	: The port to remove
//--------------------------------------------------------------------------------------------------------------------------
void System_RemoveGpioPin(int PortNumber)
{
	removePort(PortNumber);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : System_TurnOnLed
// Date (dd-mm-yyyy)    : 05.03.2012
// Function description : Turns on the Led
// In-/Output           : Led : Led to turn on
//--------------------------------------------------------------------------------------------------------------------------
void System_TurnOnLed(int Led)
{
	TurnLedOn(Led);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : System_TurnOffLed
// Date (dd-mm-yyyy)    : 05.03.2012
// Function description : Turns off the Led
// In-/Output           : Led : Led to turn off
//--------------------------------------------------------------------------------------------------------------------------
void System_TurnOffLed(int Led)
{
	TurnLedOff(Led);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : System_SetLedTrigger
// Date (dd-mm-yyyy)    : 05.03.2012
// Function description : Sets the Trigger on Led
// In-/Output           : Led 		: The Led to set the trigger on
//						: Trigger	: The trigger to set
//--------------------------------------------------------------------------------------------------------------------------
void System_SetLedTrigger(int Led, int Trigger)
{
	SetLedTrigger(Led, Trigger);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : System_ToggleLed
// Date (dd-mm-yyyy)    : 05.03.2012
// Function description : Toggles the Led. If a trigger is set, this won't work.
// In-/Output           : Led		: The Led to toggle
//--------------------------------------------------------------------------------------------------------------------------
void System_ToggleLed(int Led)
{
	if(readBrightnessFile(Led) == 0)
	{
		TurnLedOn(Led);
	}
	else if(readBrightnessFile(Led) == 1)
	{
		TurnLedOff(Led);
	}
	else
	{
		printf("Trigger set - can't toggle Led");
	}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Local functions
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : writeExportFile
// Date (dd-mm-yyyy)    : 25.02.2012
// Function description : Will write to the export file to create the port folder
// In-/Output           : PortNumber	: The port number to initialize
//--------------------------------------------------------------------------------------------------------------------------
void writeExportFile(int PortNumber)
{
	FILE *fp;
	//Check if the export file to create the GPIO pin is available
	if((fp = fopen(defExport,"ab")) == NULL)
	{
		printf("Export file can't be opened\n");
		exit(1);
	}
	//Port Number can't be more than three digits, hence why an array
	//of size 3 is used
	char set_value[3];
	//Write port number to set_value variable
	sprintf(set_value, "%d", PortNumber);
	//Go to the start of the file
	rewind(fp);
	//Write it to the file
	fwrite(&set_value, sizeof(char), 3, fp);
	//Close the file or DIE
	fclose(fp);
	//Print that success have been achieved!
	printf("Created /sys/class/gpio/gpio%d\n", PortNumber);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : writeDirectionFile
// Date (dd-mm-yyyy)    : 25.02.2012
// Function description : Will write the direction to the direction file
// In-/Output           : PortNumber 	: The port to write the direction to
//						: Direction		: The direction to set
//--------------------------------------------------------------------------------------------------------------------------
void writeDirectionFile(int PortNumber, int Direction)
{
	//Check if direction is set to input or output, if not, exit with error
	if(Direction != 1 && Direction != 0)
	{
		printf("Please select a valid direction, exiting");
		exit(1);
	}
	FILE *fp;
	//Write the path to the Direction file
	writeGpioPath(PortNumber, defSelectDirection);
	#ifdef DEBUG
	//To check what the path is
	printf("%s\n", result);
	#endif
	//Try to open the direction file
	if((fp = fopen(result,"ab")) == NULL)
	{
		printf("Can't open direction file\n");
		exit(1);
	}
	//Go to the start of the file
	rewind(fp);
	//Check which direction is selected
	if(Direction == 1) //Input
	{
		fwrite(defPinIn, sizeof(char), 2, fp);
		printf("Direction set to input\n");
	}
	else //Output - can do else here, because there is a check earlier to ensure integrity
	{
		fwrite(defPinOut, sizeof(char), 3, fp);
		printf("Direction set to output\n");
	}
	//Close the file
	fclose(fp);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : writeValueFile
// Date (dd-mm-yyyy)    : 25.02.2012
// Function description : Writes the initial value to the value file
// In-/Output           : PortNumber	: The port to write the value to
//						: Value			: The initial value
//--------------------------------------------------------------------------------------------------------------------------
void writeValueFile(int PortNumber, int Value)
{
	FILE *fp;
	//Check if value is 1 or 0
	if(Value != 1 && Value != 0)
	{
		printf("Please select a valid value, exiting");
		exit(1);
	}
	//Write the path to the Value file
	writeGpioPath(PortNumber, defSelectValue);
	#ifdef DEBUG
	//Print out the path to the value file
	printf("%s\n", result);
	#endif
	//Check if file can be opened
	if((fp = fopen(result,"ab")) == NULL)
	{
		printf("Can't open value file\n");
		exit(1);
	}
	//Go to the start of the file
	rewind(fp);
	//Check whether to set value high or low
	if(Value == 1) //High
	{
		fwrite(defValueHigh, sizeof(char), 1, fp);
		printf("Value set to High\n");
	}
	else //Low
	{
		fwrite(defValueLow, sizeof(char), 1, fp);
		printf("Value set to Low\n");
	}
	//Close file
	fclose(fp);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : writePath
// Date (dd-mm-yyyy)    : 25.02.2012
// Function description : Writes the path from the given parameters
// In-/Output           : PortNumber	: The port to write the path to
//						: Select		: Select direction or value - defSelectDirection or defSelectValue
//--------------------------------------------------------------------------------------------------------------------------
void writeGpioPath(int PortNumber, int Select)
{
	if(Select == defSelectDirection)
	{
		sprintf(result, "%s%d%s", defPath, PortNumber, defDirection);
	}
	else if(Select == defSelectValue)
	{
		sprintf(result, "%s%d%s", defPath, PortNumber, defValue);
	}
}
//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : readFile
// Date (dd-mm-yyyy)    : 25.02.2012
// Function description : Reads the current state of the PortNumber
// In-/Output           : PortNumber	: The PortNumber to get the value from
//--------------------------------------------------------------------------------------------------------------------------
int readValueFile(int PortNumber)
{
	FILE *fp;
	//To be able to get an int from a char.
	char readValue;
	//Value read, as a char
	int Value;
	//Get the path to the wanted port number
	writeGpioPath(PortNumber, defSelectValue);
	#ifdef DEBUG
	//Print out the path to the value file
	printf("%s\n", result);
	#endif
	//Open the value file
	if((fp = fopen(result,"rt")) == NULL)
	{
		printf("Can't open value file\n");
		exit(1);
	}
	//Read the value from the file
	Value = getc(fp);
	//Cast to char
	readValue = Value;
	//Go char - '0', this is a wtf but converts to int value instead of char value
	Value = readValue  - '0';
	return Value;
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : removePort
// Date (dd-mm-yyyy)    : 26.02.2012
// Function description : Removes the GPIO port
// In-/Output           : PortNumber	: The port number to remove
//--------------------------------------------------------------------------------------------------------------------------
void removePort(int PortNumber)
{
	FILE *fp;
	//To write out the portnumber
	char set_value[3];
	//Check if the export file to create the GPIO pin is available
	if((fp = fopen(defUnexport,"ab")) == NULL)
	{
		printf("Unexport file can't be opened\n");
		exit(1);
	}
	//Go to the start of the file
	rewind(fp);
	//Convert the integer to a char array
	sprintf(set_value, "%d", PortNumber);
	//Write out the value to the unexport file
	fwrite(&set_value, sizeof(char), 3, fp);
	//Write out succes has been achieved
	printf("Removed GPIO%d\n", PortNumber);
	//Close the file
	fclose(fp);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : TurnLedOn
// Date (dd-mm-yyyy)    : 05.03.2012
// Function description : Turns on the selected Led
// In-/Output           : Led	: Led to turn on
//--------------------------------------------------------------------------------------------------------------------------
void TurnLedOn(int Led)
{
	FILE *fp;
	writeLedPath(Led, defSelectBrightness);
	#ifdef debug
	printf("%s\n");
	#endif
	//Check if the led brightness file is available
	if((fp = fopen(result,"ab")) == NULL)
	{
		printf("Brightness file can't be opened\n");
		exit(1);
	}
	//Go to the start of the file
	rewind(fp);
	//Write out the value to the unexport file
	fwrite(defLedOn, sizeof(char), 1, fp);
	//Write out succes has been achieved
	printf("Turned on Led %d\n", Led);
	//Close the file
	fclose(fp);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : TurnLedOff
// Date (dd-mm-yyyy)    : 05.03.2012
// Function description : Turns off the selected Led
// In-/Output           : Led	: Led to turn off
//--------------------------------------------------------------------------------------------------------------------------
void TurnLedOff(int Led)
{
	FILE *fp;
	writeLedPath(Led, defSelectBrightness);
	#ifdef debug
	printf("%s\n");
	#endif
	//Check if the led brightness file is available
	if((fp = fopen(result,"ab")) == NULL)
	{
		printf("Brightness file can't be opened\n");
		exit(1);
	}
	//Go to the start of the file
	rewind(fp);
	//Write out the value to the unexport file
	fwrite(defLedOff, sizeof(char), 1, fp);
	//Write out succes has been achieved
	printf("Turned off Led %d\n", Led);
	//Close the file
	fclose(fp);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : SetLedTrigger
// Date (dd-mm-yyyy)    : 05.03.2012
// Function description : Sets the trigger on a led.
// In-/Output           : Led		: Led to set trigger on
//						: Trigger 	: Trigger to set
//--------------------------------------------------------------------------------------------------------------------------
void SetLedTrigger(int Led, int Trigger)
{
	FILE *fp;
	writeLedPath(Led, defSelectTrigger);
	char trigger_value[10];
	#ifdef debug
	printf("%s\n");
	#endif
	//Check if the led brightness file is available
	if((fp = fopen(result,"ab")) == NULL)
	{
		printf("Trigger file can't be opened\n");
		exit(1);
	}
	//Go to the start of the file
	rewind(fp);
	if(Trigger == defTriggerNone)
	{
		sprintf(trigger_value, "none");
	}
	else if(Trigger == defTriggerTimer)
	{
		sprintf(trigger_value, "timer");
	}
	else if(Trigger == defTriggerHeartbeat)
	{
		sprintf(trigger_value, "heartbeat");
	}
	else if(Trigger == defTriggerDefaultOn)
	{
		sprintf(trigger_value, "default-on");
	}
	else if(Trigger == defTriggerMmc0)
	{
		sprintf(trigger_value, "mmc0");
	}
	//Write out the value to the unexport file
	fwrite(&trigger_value, sizeof(char), 10, fp);
	//Write out succes has been achieved
	printf("Set trigger\n");
	//Close the file
	fclose(fp);
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : writeLedPath
// Date (dd-mm-yyyy)    : 05.03.2012
// Function description : Writes out the path to a Led
// In-/Output           : Led		: The led to get the path to
//						: Selection	: The attribute to set the path to
//--------------------------------------------------------------------------------------------------------------------------
void writeLedPath(int Led, int Selection)
{
	if(Selection == defSelectTrigger)
	{
		if(Led == defLedA)
		{
			sprintf(result, "%s%s%s", defLedPath, "a", defLedTrigger);
		}
		else if(Led == defLedB)
		{
			sprintf(result, "%s%s%s", defLedPath, "b", defLedTrigger);
		}
		else if(Led == defLedSys)
		{
			sprintf(result, "%s%s%s", defLedPath, "sys", defLedTrigger);
		}
	}
	else if(Selection == defSelectBrightness)
	{
		if(Led == defLedA)
		{
			sprintf(result, "%s%s%s", defLedPath, "a", defLedBrightness);
		}
		else if(Led == defLedB)
		{
			sprintf(result, "%s%s%s", defLedPath, "b", defLedBrightness);
		}
		else if(Led == defLedSys)
		{
			sprintf(result, "%s%s%s", defLedPath, "sys", defLedBrightness);
		}
	}
}

//--------------------------------------------------------------------------------------------------------------------------
// Function Name        : readBrightnessFile
// Date (dd-mm-yyyy)    : 05.03.2012
// Function description : Reads the current state of the Brightness file
// In-/Output           : Led	: The Led to get the value from
//--------------------------------------------------------------------------------------------------------------------------
int readBrightnessFile(int Led)
{
	FILE *fp;
	//To be able to get an int from a char.
	char readValue;
	//Value read, as a char
	int Value;
	//Get the path to the wanted port number
	writeLedPath(Led, defSelectBrightness);
	#ifdef DEBUG
	//Print out the path to the value file
	printf("%s\n", result);
	#endif
	//Open the value file
	if((fp = fopen(result,"rt")) == NULL)
	{
		printf("Can't open brightness file\n");
		exit(1);
	}
	//Read the value from the file
	Value = getc(fp);
	//Cast to char
	readValue = Value;
	//Go char - '0', this is a wtf but converts to int value instead of char value
	Value = readValue - '0';
	return Value;
}
